#include "tcpmanager.h"
#include "usermanager.h"

#include <QAbstractSocket>
#include <QJsonDocument>
#include <QJsonObject>
#include <QDebug>

TcpManager::TcpManager() : m_host(""), m_port(0), m_b_recv_pending(false), m_message_id(0), m_message_len(0)
{
    // 进行连接(在套接字尝试建立连接时，需要处理connected()信号。这个信号在连接成功建立后被发出)
    QObject::connect(&m_socket, &QTcpSocket::connected, [&]() {
        qDebug() << "Tcp Connected to ChatSeerver......";

        // 连接成功建立后切换消息发送界面
        emit sig_con_success(true);
    });

    // 处理数据
    QObject::connect(&m_socket, &QTcpSocket::readyRead, [&]() {
        // 当有数据可读时，读取数据，并将所有数据追加到接受缓冲区里面
        m_buffer.append( m_socket.readAll() );

        QDataStream stream(&m_buffer, QIODevice::ReadOnly);
        stream.setVersion(QDataStream::Qt_5_15);

        forever {
            // 先解析消息头
            if (!m_b_recv_pending) {
                // 检测缓冲区的数据长度是否能够解析出来一个消息头
                if ( m_buffer.size() < static_cast<int>(sizeof(quint16) * 2) ) {
                    return ; // 接受到的数据不够，继续等待
                }
            }

            // 读取消息id和消息长度，但不从缓冲区里面移除
            stream >> m_message_id >> m_message_len;

            // 读取完毕之后，将m_buffer的前4个字节移除(消息头)
            m_buffer = m_buffer.mid(sizeof(quint16) * 2);

            // 打印读取的消息id和消息长度
            qDebug() << "m_message_id = " << m_message_id << " m_message_len = " << m_message_len;

            // m_buffer剩余长度是否满足消息体长度，不满足则退出继续等待接受
            if ( m_buffer.size() < m_message_len) {
                m_b_recv_pending = true;
                return ;
            }

            m_b_recv_pending = false;

            // 读取消息体
            QByteArray message_body = m_buffer.mid(0, m_message_len);
            qDebug() << "message_body = " << message_body;

            m_buffer = m_buffer.mid(m_message_len);

            // 处理接收到的数据
            handleMsg(static_cast<ReqId>(m_message_id),  message_body);
        }
    });

    // 处理连接错误
    QObject::connect(&m_socket, QOverload<QAbstractSocket::SocketError>::of(&QTcpSocket::errorOccurred), [&](QAbstractSocket::SocketError socketError) {
           Q_UNUSED(socketError)
           qDebug() << "Error:" << m_socket.errorString();
    });

    // 处理连接断开
    QObject::connect(&m_socket, &QTcpSocket::disconnected, [&]() {
        qDebug() << "disconnect from server......";
    });

    // 发送数据
    QObject::connect(this, &TcpManager::sig_send_data, this, &TcpManager::slot_send_data);

    // 注册消息
    initHandlers();
}

// 处理ID_CHAT_LOGIN_RSP(登陆聊天服务器回包)
void TcpManager::handleChatLoginRsp(ReqId id, QByteArray data)
{
    qDebug() << "handle id is " << id << " data is " << data;

    // 进行json的反序列化
    QJsonDocument jsonDoc = QJsonDocument::fromJson(data);
    if (jsonDoc.isNull()) {
        qDebug() << "create QJsonDocument failed......";
        return ;
    }

    QJsonObject jsonObj = jsonDoc.object();
    qDebug()<< "data jsonobj is " << jsonObj;

    if (!jsonObj.contains("error")) {
        int err = ErrorCodes::ERR_JSON;
        qDebug() << "Login failed, error is json Parse Err " << err;
        emit sig_login_failed(err);
        return ;
    }

    int err = jsonObj["error"].toInt();
    if (err != ErrorCodes::SUCCESS) {
        qDebug() << "Login Failed, err is " << err ;
        emit sig_login_failed(err);
        return;
    }

    auto uid = jsonObj["uid"].toInt();
    auto name = jsonObj["name"].toString();
    auto nick = jsonObj["nick"].toString();
    auto icon = jsonObj["icon"].toString();
    auto sex = jsonObj["sex"].toInt();
    auto user_info = std::make_shared<UserInfo>(uid, name, nick, icon, sex);


    // 将用户的数据通过UserManager类来管理，减少耦合性
    UserManager::getInstance()->setUserInfo(user_info);
    UserManager::getInstance()->setToken(jsonObj["token"].toString());

    if (jsonObj.contains("apply_list")) {
        UserManager::getInstance()->appendApplyList(jsonObj["apply_list"].toArray());
    }

    // 添加好友列表
    if (jsonObj.contains("friend_list")) {
        UserManager::getInstance()->appendFriendList(jsonObj["friend_list"].toArray());
    }

    // 发送切换到聊天界面的信号
    emit sig_swich_chatdlg();
}

// 处理ID_SEARCH_USER_RSP(搜索用户回包)
void TcpManager::handleSearchUserRsp(ReqId id, QByteArray data)
{
    qDebug() << "handle id is " << id << " data is " << data;
    // 将QByteArray转换为QJsonDocument
    QJsonDocument jsonDoc = QJsonDocument::fromJson(data);

    // 检查转换是否成功
    if (jsonDoc.isNull()) {
        qDebug() << "Failed to create QJsonDocument......";
        return;
    }

    QJsonObject jsonObj = jsonDoc.object();

    if (!jsonObj.contains("error")) {
        int err = ErrorCodes::ERR_JSON;
        qDebug() << "Login Failed, err is Json Parse Err......" << err;

        emit sig_user_search(nullptr);
        return;
    }

    int err = jsonObj["error"].toInt();
    if (err != ErrorCodes::SUCCESS) {
        qDebug() << "Login Failed, err is " << err;
        emit sig_user_search(nullptr);
        return;
    }
    auto search_info =  std::make_shared<SearchInfo>(jsonObj["uid"].toInt(), jsonObj["name"].toString(),
                                                    jsonObj["nick"].toString(), jsonObj["desc"].toString(),
                                                    jsonObj["sex"].toInt(), jsonObj["icon"].toString());

    emit sig_user_search(search_info);
}

// 处理ID_NOTIFY_ADD_FRIEND_REQ(通知用户添加好友申请)
void TcpManager::handleNotifyAddFriendReq(ReqId id, QByteArray data)
{
    qDebug() << "handle id is " << id << " data is " << data;
    // 将QByteArray转换为QJsonDocument
    QJsonDocument jsonDoc = QJsonDocument::fromJson(data);

    // 检查转换是否成功
    if (jsonDoc.isNull()) {
        qDebug() << "Failed to create QJsonDocument......";
        return;
    }

    QJsonObject jsonObj = jsonDoc.object();

    if (!jsonObj.contains("error")) {
        int err = ErrorCodes::ERR_JSON;
        qDebug() << "Login Failed, err is Json Parse Err......" << err;

        emit sig_user_search(nullptr);
        return;
    }

    int err = jsonObj["error"].toInt();
    if (err != ErrorCodes::SUCCESS) {
        qDebug() << "Login Failed, err is " << err;
        emit sig_user_search(nullptr);
        return;
    }

    int from_uid = jsonObj["applyuid"].toInt();
    QString name = jsonObj["name"].toString();
    QString desc = jsonObj["desc"].toString();
    QString icon = jsonObj["icon"].toString();
    QString nick = jsonObj["nick"].toString();
    int sex = jsonObj["sex"].toInt();

    auto apply_info = std::make_shared<AddFriendApply>(from_uid, name, desc, icon, nick, sex);

    emit sig_friend_apply(apply_info);
}

// 处理ID_NOTIFY_AUTH_FRIEND_REQ(通知用户认证好友申请)
void TcpManager::handleNotifyAuthFriendReq(ReqId id, QByteArray data)
{
    qDebug() << "handle id is " << id << " data is " << data;
    // 将QByteArray转换为QJsonDocument
    QJsonDocument jsonDoc = QJsonDocument::fromJson(data);

    // 检查转换是否成功
    if (jsonDoc.isNull()) {
        qDebug() << "Failed to create QJsonDocument.";
        return;
    }

    QJsonObject jsonObj = jsonDoc.object();
    if (!jsonObj.contains("error")) {
        int err = ErrorCodes::ERR_JSON;
        qDebug() << "Auth Friend Failed, err is " << err;
        return;
    }

    int err = jsonObj["error"].toInt();
    if (err != ErrorCodes::SUCCESS) {
        qDebug() << "Auth Friend Failed, err is " << err;
        return;
    }

    int from_uid = jsonObj["fromuid"].toInt();
    QString name = jsonObj["name"].toString();
    QString nick = jsonObj["nick"].toString();
    QString icon = jsonObj["icon"].toString();
    int sex = jsonObj["sex"].toInt();

    auto auth_info = std::make_shared<AuthInfo>(from_uid,name, nick, icon, sex);

    emit sig_add_auth_friend(auth_info);
}

// 处理ID_ADD_FRIEND_RSP(申请添加好友的回复)
void TcpManager::handleAddFriendRsp(ReqId id, QByteArray data)
{
    qDebug() << "handle id is " << id << " data is " << data;
    // 将QByteArray转换为QJsonDocument
    QJsonDocument jsonDoc = QJsonDocument::fromJson(data);

    // 检查转换是否成功
    if (jsonDoc.isNull()) {
        qDebug() << "Failed to create QJsonDocument.";
        return;
    }

    QJsonObject jsonObj = jsonDoc.object();

    if (!jsonObj.contains("error")) {
        int err = ErrorCodes::ERR_JSON;
        qDebug() << "Add Friend Failed, err is Json Parse Err" << err;
        return;
    }

    int err = jsonObj["error"].toInt();
    if (err != ErrorCodes::SUCCESS) {
        qDebug() << "Add Friend Failed, err is " << err;
        return;
    }

    qDebug() << "Add Friend Success " ;
}

// 处理ID_AUTH_FRIEND_RSP(认证好友回复)
void TcpManager::handleAuthFriendRsp(ReqId id, QByteArray data)
{
    qDebug() << "handle id is " << id << " data is " << data;
    // 将QByteArray转换为QJsonDocument
    QJsonDocument jsonDoc = QJsonDocument::fromJson(data);

    // 检查转换是否成功
    if (jsonDoc.isNull()) {
        qDebug() << "Failed to create QJsonDocument.";
        return;
    }

    QJsonObject jsonObj = jsonDoc.object();

    if (!jsonObj.contains("error")) {
        int err = ErrorCodes::ERR_JSON;
        qDebug() << "Auth Friend Failed, err is Json Parse Err" << err;
        return;
    }

    int err = jsonObj["error"].toInt();
    if (err != ErrorCodes::SUCCESS) {
        qDebug() << "Auth Friend Failed, err is " << err;
        return;
    }

    auto name = jsonObj["name"].toString();
    auto nick = jsonObj["nick"].toString();
    auto icon = jsonObj["icon"].toString();
    auto sex = jsonObj["sex"].toInt();
    auto uid = jsonObj["uid"].toInt();
    auto rsp = std::make_shared<AuthRsp>(uid, name, nick, icon, sex);
    emit sig_auth_rsp(rsp);

    qDebug() << "Auth Friend Success...... " ;
}

// 处理ID_TEXT_CHAT_MSG_RSP(文本聊天信息回复)
void TcpManager::handleTextChatMsgRsp(ReqId id, QByteArray data)
{
    qDebug() << "handle id is " << id << " data is " << data;
    // 将QByteArray转换为QJsonDocument
    QJsonDocument jsonDoc = QJsonDocument::fromJson(data);

    // 检查转换是否成功
    if (jsonDoc.isNull()) {
        qDebug() << "Failed to create QJsonDocument.";
        return;
    }

    QJsonObject jsonObj = jsonDoc.object();

    if (!jsonObj.contains("error")) {
        int err = ErrorCodes::ERR_JSON;
        qDebug() << "Chat Msg Rsp Failed, err is Json Parse Err" << err;
        return;
    }

    int err = jsonObj["error"].toInt();
    if (err != ErrorCodes::SUCCESS) {
        qDebug() << "Chat Msg Rsp Failed, err is " << err;
        return;
    }

    qDebug() << "Receive Text Chat Rsp Success " ;
    // ui设置送达等标记 todo...
}

// 处理ID_NOTIFY_TEXT_CHAT_MSG_REQ(通知用户文本聊天信息)
void TcpManager::handleNotifyTextChatMsgReq(ReqId id, QByteArray data)
{
    qDebug() << "handle id is " << id << " data is " << data;
    // 将QByteArray转换为QJsonDocument
    QJsonDocument jsonDoc = QJsonDocument::fromJson(data);

    // 检查转换是否成功
    if (jsonDoc.isNull()) {
        qDebug() << "Failed to create QJsonDocument......";
        return;
    }

    QJsonObject jsonObj = jsonDoc.object();

    if (!jsonObj.contains("error")) {
        int err = ErrorCodes::ERR_JSON;
        qDebug() << "Notify Chat Msg Failed, err is Json Parse Err" << err;
        return;
    }

    int err = jsonObj["error"].toInt();
    if (err != ErrorCodes::SUCCESS) {
        qDebug() << "Notify Chat Msg Failed, err is " << err;
        return;
    }

    qDebug() << "Receive Text Chat Notify Success......" ;
    auto msg_ptr = std::make_shared<TextChatMsg>(jsonObj["fromuid"].toInt(),
                                                 jsonObj["touid"].toInt(),jsonObj["text_array"].toArray());
    emit sig_text_chat_msg(msg_ptr);
}

// 注册消息的回调
void TcpManager::initHandlers()
{
    // 登陆聊天服务器回包
    m_handlers.insert(ID_CHAT_LOGIN_RSP, std::bind(&TcpManager::handleChatLoginRsp, this, std::placeholders::_1,
                                                    std::placeholders::_2)
    );

    // 搜索用户回包
    m_handlers.insert(ID_SEARCH_USER_RSP, std::bind(&TcpManager::handleSearchUserRsp, this, std::placeholders::_1,
                                                    std::placeholders::_2)
    );

    // 通知用户添加好友申请
    m_handlers.insert(ID_NOTIFY_ADD_FRIEND_REQ, std::bind(&TcpManager::handleNotifyAddFriendReq, this, std::placeholders::_1,
                                                    std::placeholders::_2)
    );

    // 通知用户认证好友申请
    m_handlers.insert(ID_NOTIFY_AUTH_FRIEND_REQ, std::bind(&TcpManager::handleNotifyAuthFriendReq, this, std::placeholders::_1,
                                                    std::placeholders::_2)
    );

    // 申请添加好友回复
    m_handlers.insert(ID_ADD_FRIEND_RSP, std::bind(&TcpManager::handleAddFriendRsp, this, std::placeholders::_1,
                                                    std::placeholders::_2)
    );

    // 认证好友回复
    m_handlers.insert(ID_AUTH_FRIEND_RSP, std::bind(&TcpManager::handleAuthFriendRsp, this, std::placeholders::_1,
                                                    std::placeholders::_2)
    );

    // 文本聊天信息回复
    m_handlers.insert(ID_TEXT_CHAT_MSG_RSP,  std::bind(&TcpManager::handleTextChatMsgRsp, this, std::placeholders::_1,
                                        std::placeholders::_2)
    );

    // 通知用户文本聊天信息
    m_handlers.insert(ID_NOTIFY_TEXT_CHAT_MSG_REQ, std::bind(&TcpManager::handleNotifyTextChatMsgReq, this, std::placeholders::_1,
                                               std::placeholders::_2)
    );
}

// 调用消息的会回调来处理数据
void TcpManager::handleMsg(ReqId id, QByteArray data)
{
    auto it = m_handlers.find(id);
    if (it == m_handlers.end()) {
        qDebug() << "not found id [" << id << "] to handle";
        return;
    }

    // 消息回调
    it.value()(id, data);
}

// 处理Tcp连接
void TcpManager::slot_tcp_connect(ServerInfo server_info)
{
    qDebug() << "receive tcp connect signal";
    // 尝试连接到服务器
    qDebug() << "Connecting to server...";
    m_host = server_info.Host;
    m_port = static_cast<uint16_t>(server_info.Port.toUInt());
    qDebug() << "TcpManager::slot_tcp_connect::m_port = " << m_port;
    m_socket.connectToHost(server_info.Host, m_port);
}

// 处理数据发送
void TcpManager::slot_send_data(ReqId req_id, QByteArray data_bytes)
{
    uint16_t id = req_id;

    // 计算长度
    quint16 len = static_cast<quint16>(data_bytes.length());

    // 创建一个QByteArray用于存储要发送的所有数据
    QByteArray data_block;
    QDataStream out(&data_block, QIODevice::WriteOnly);
    // 设置数据流使用网络字节序
    out.setByteOrder(QDataStream::BigEndian);

    // 写入id和产犊
    out << id << len;
    data_block.append(data_bytes);

    // 发送数据
    m_socket.write(data_block);

    qDebug() << "TcpManager send byte data is " << data_block;
}
